// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: gekim

#pragma once

// std
#include <map>
#include <memory>
#include <regex>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>

// internal
#include "coin2/base/log.h"
#include "coin2/exchange/base/feed/processor.h"
#include "coin2/exchange/base/market/enums.h"
#include "coin2/exchange/prex_base/feed_v1/update.h"
#include "coin2/flow/symbol_group.h"

namespace coin2::exchange::prex_base::feed_v1 {
namespace impl {
using namespace std::string_literals;
using coin2::exchange::base::market::ExchangeType;
using coin2::exchange::base::market::MarketType;
using coin2::exchange::base::symbology::IProduct;
using coin2::exchange::base::feed::IFeedSubscriber;

class PrexBaseFeedProcessor
    : public coin2::exchange::base::feed::FeedParsingProcessor {
 public:
  explicit PrexBaseFeedProcessor(
      const std::string& system_name, const MarketExchangeApi& mea,
      const coin2::exchange::di::ConstantInjection& ci,
      const feed::RawParserConfig& config)
      : FeedParsingProcessor(
            system_name, mea, ci, config,
            "cc/coin2/exchange/prex_base/feed_v1/schema.json") {}

  void OnTopicRecord(const base::executor::TopicRecordPacket& packet) override;

  void AddProduct(const IProduct& product,
                  IFeedSubscriber* subscriber) override {
    coin2::exchange::base::feed::FeedParsingProcessor::AddProduct(product,
                                                                  subscriber);
    const auto& native_symbol = product.feed_native_symbol();
    CHECK_EQ(native_to_topics_.count(native_symbol), 0);
    auto group = flow::SymbolGroupConfig().GetGroupForRelativeNorm(
        upd_mgr_.mea(), product.relative_norm());
    std::set<std::string> topics;
    // Assume there will be no more than 2 workers.
    topics.insert(upd_mgr_.mea().SnakeString() + "_" + group + "1");
    topics.insert(upd_mgr_.mea().SnakeString() + "_" + group + "2");
    native_to_topics_[native_symbol] = topics;
  }

 private:
  std::unordered_map<std::string, std::set<std::string>> native_to_topics_;
};

struct PrexChannel {
  std::string type;
  std::string symbol;

  static PrexChannel Parse(const std::string& ch) {
    /*
    "market/orderBook:BTCUSD.PERP"
    "market/trade:BTCUSD.PERP"
    "market/instrument"
    */
    std::vector<std::string> splitted;
    splitted = Split(ch, ":");
    if (splitted.size() == 1) {
      return PrexChannel{splitted.front(), std::string()};
    } else if (splitted.size() == 2) {
      return PrexChannel{splitted.front(), splitted.back()};
    } else {
      NOTREACHED() << "unknown channel: " << ch;
    }
  }
};
}  // namespace impl
using impl::PrexBaseFeedProcessor;
}  // namespace coin2::exchange::prex_base::feed_v1
